package com.derbysoft.ota.application.translator.rq;

import java.util.List;

import javax.annotation.Nullable;

import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.ota.application.util.Dates;
import com.derbysoft.ota.interfaces.protocol._2009a.OTAHotelAvailRQ;
import com.derbysoft.ota.interfaces.protocol._2009a.RoomStayCandidateType;
import com.derbysoft.ota.interfaces.protocol._2009a.AvailRequestSegmentsType.AvailRequestSegment;
import com.derbysoft.ota.interfaces.protocol._2009a.GuestCountType.GuestCount;
import com.derbysoft.ota.interfaces.protocol._2009a.HotelSearchCriteriaType.Criterion;
import com.derbysoft.ota.interfaces.protocol._2009a.ItemSearchCriterionType.HotelRef;
import com.derbysoft.remote.dswitch.generic.constants.AgeQualifyingType;
import com.derbysoft.remote.dswitch.hotel.dto.GuestCountDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelAvailCriteriaDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelMultiProviderAvailRQ;
import com.derbysoft.remote.dswitch.hotel.dto.HotelRefDTO;
import com.derbysoft.remote.dswitch.hotel.dto.RoomStayCandidateDTO;
import com.derbysoft.remote.dswitch.hotel.dto.StayDateRangeDTO;
import com.derbysoft.remote.share.LanguageType;
import com.google.common.base.Function;
import com.google.inject.Inject;
import com.googlecode.functionalcollections.FunctionalIterables;

public class HotelAvailRQTranslator implements Translator<OTAHotelAvailRQ, HotelMultiProviderAvailRQ> {

    private Translator<String, LanguageType> languageTypeTranslator;
    private Translator<String, AgeQualifyingType> ageQualifyingTypeTranslator;

	@Inject
	public HotelAvailRQTranslator(Translator<String, LanguageType> languageTypeTranslator,
								  Translator<String, AgeQualifyingType> ageQualifyingTypeTranslator) {
		this.languageTypeTranslator = languageTypeTranslator;
		this.ageQualifyingTypeTranslator = ageQualifyingTypeTranslator;
	}

	public HotelMultiProviderAvailRQ translate(OTAHotelAvailRQ source) {
        HotelMultiProviderAvailRQ switchRQ = new HotelMultiProviderAvailRQ();
        HotelAvailCriteriaDTO criteria = new HotelAvailCriteriaDTO();
        
        AvailRequestSegment segment = 
        	FunctionalIterables.make(source.getAvailRequestSegments().getAvailRequestSegment())
        					   .messagedIterator("Please provide at least 1 avail request segment.").next();
        Criterion otaCriterion = 
        	FunctionalIterables.make(segment.getHotelSearchCriteria().getCriterion())
        					   .messagedIterator("Please provide at least 1 hotel search criterion.").next();
        criteria.setHotelRef(hotelRef(otaCriterion));
        criteria.setLanguageType(language(source));
        criteria.setRoomStayCandidates(roomStayCandidate(segment));
        criteria.setStayDateRange(stayDateRange(segment));
        switchRQ.setAvailCriteria(criteria);
        return switchRQ;
	}

    private StayDateRangeDTO stayDateRange(AvailRequestSegment segment) {
        return new StayDateRangeDTO(
            Dates.parse(segment.getStayDateRange().getStart()),
            Dates.parse(segment.getStayDateRange().getEnd())
        );
    }

    private RoomStayCandidateDTO roomStayCandidate(AvailRequestSegment segment) {
        RoomStayCandidateDTO switchRoomStayCandidates = new RoomStayCandidateDTO();
        RoomStayCandidateType otaRoomStayCandidate = segment.getRoomStayCandidates().getRoomStayCandidate().iterator().next();
        switchRoomStayCandidates.setNumberOfUnits(otaRoomStayCandidate.getQuantity());
        List<GuestCountDTO> guestCounts = FunctionalIterables.make(otaRoomStayCandidate.getGuestCounts().getGuestCount()).map(new Function<GuestCount, GuestCountDTO>() {
            public GuestCountDTO apply(@Nullable GuestCount from) {
                return new GuestCountDTO(
                    ageQualifyingTypeTranslator.translate(from.getAgeQualifyingCode()),
                    from.getCount()
                );
            }
        }).toList();
        switchRoomStayCandidates.setGuestCounts(guestCounts);
        return switchRoomStayCandidates;
    }

    private LanguageType language(OTAHotelAvailRQ source) {
        return languageTypeTranslator.translate(source.getPrimaryLangID());
    }

    private HotelRefDTO hotelRef(Criterion otaCriterion) {
        HotelRef hotelRefSource = otaCriterion.getHotelRef().iterator().next();
        return new HotelRefDTO(hotelRefSource.getHotelCode());
    }

}
